#include <iostream>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string>

#define PAGE_SIZE 4096

// write_map filename
int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        std::cout << "Usage: " << argv[0] << " filename" << std::endl;
        return 1;
    }

    // 1. 打开目标文件，mmap需要你自己打开文件: 读写打开、不存在就创建、清空方式
    std::string filename = argv[1];
    int fd = ::open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666);
    if(fd < 0)
    {
        std::cout << "Failed to open file: " << filename << std::endl;
        return 2; 
    }

    // 2. 我们需要手动调整一个文件的大小，填充方便我们进行合法映射，文件默认的用0
    //    不会像write一样自动调整文件的大小
    if(ftruncate(fd, PAGE_SIZE) == -1)
    {
        std::cout << "Failed to truncate file: " << filename << std::endl;
        return 3; 
    }

    // 3. 文件映射
    char* shmaddr = (char*)::mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if(shmaddr == MAP_FAILED)
    {
        std::cout << "Failed to mmap file: " << filename << std::endl;
        return 4; 
    }

    // 4. 进行写文件操作
    for(char ch = 'a'; ch <= 'z'; ch++)
    {
        shmaddr[ch - 'a'] = ch;
        sleep(1);
    }

    // 5. 关闭文件映射
    if(::munmap(shmaddr, PAGE_SIZE) == -1)
    {
        std::cout << "Failed to munmap file: " << filename << std::endl;
        return 5;
    }

    // 6. 关闭文件
    ::close(fd);

    return 0;
}